// Text of project Altered States written on 3/20/96 at 1:02 PM
// Beginning of file protoEvent

// Before Script for "_userproto000"
//	Newton Developer Technical Support Sample Code
//	protoEvent - An NTK Finite State Machine User Proto
//	by Jim Schram, Newton Developer Technical Support
//	Copyright ©1996 Apple Computer, Inc.  All rights reserved.
//	
//	You may incorporate this sample code into your applications without
//	restriction.  This sample code has been provided "AS IS" and the
//	responsibility for its operation is 100% yours.  You are not
//	permitted to modify and redistribute the source as "DTS Sample Code."
//	If you are going to re-distribute the source, we require that you
//	make it clear in the source that the code was descended from
//	Apple-provided sample code, but that you've made changes.


_userproto000 :=
    {viewBounds: {left: 8, top: 16, right: 96, bottom: 32}, _proto: @218};


constant |layout_protoEvent| := _userproto000;
// End of file protoEvent
// Beginning of file protoState

// Before Script for "_userproto001"
//	Newton Developer Technical Support Sample Code
//	protoState - An NTK Finite State Machine User Proto
//	by Jim Schram, Newton Developer Technical Support
//	Copyright ©1996 Apple Computer, Inc.  All rights reserved.
//	
//	You may incorporate this sample code into your applications without
//	restriction.  This sample code has been provided "AS IS" and the
//	responsibility for its operation is 100% yours.  You are not
//	permitted to modify and redistribute the source as "DTS Sample Code."
//	If you are going to re-distribute the source, we require that you
//	make it clear in the source that the code was descended from
//	Apple-provided sample code, but that you've made changes.


_userproto001 :=
    {viewBounds: {left: 8, top: 16, right: 112, bottom: 56}, _proto: @473};


constant |layout_protoState| := _userproto001;
// End of file protoState
// Beginning of file protoFSM

// Before Script for "_userproto002"
//	Newton Developer Technical Support Sample Code
//	protoFSM - An NTK Finite State Machine User Proto
//	by Jim Schram, Newton Developer Technical Support
//	Copyright ©1996 Apple Computer, Inc.  All rights reserved.
//	
//	You may incorporate this sample code into your applications without
//	restriction.  This sample code has been provided "AS IS" and the
//	responsibility for its operation is 100% yours.  You are not
//	permitted to modify and redistribute the source as "DTS Sample Code."
//	If you are going to re-distribute the source, we require that you
//	make it clear in the source that the code was descended from
//	Apple-provided sample code, but that you've made changes.

kFSMCleanUpFunc := func(fsmFrame)
begin
	local fsmSymbol, stateSymbol, eventSymbol, hasGenesisState;
	
	RemoveSlot(fsmFrame._proto, '_proto);
	RemoveSlot(fsmFrame._proto, 'viewBounds);
	RemoveSlot(fsmFrame, 'viewBounds);
	
	fsmFrame.fsm_private_states := {	};
	
	if not fsmSymbol := GetSlot(fsmFrame, 'declareSelf) then
		begin
			fsmSymbol := 'unknown;
			print("A protoFSM implementation is unnamed (you forgot the declareSelf slot).");
		end;
	
	if fsmFrame.stepChildren then
		foreach stateFrame in fsmFrame.stepChildren do
			begin
				RemoveSlot(stateFrame, '_proto);
				RemoveSlot(stateFrame, 'viewBounds);
				
				if not stateSymbol := GetSlot(stateFrame, 'declareSelf) then
					begin
						stateSymbol := 'unknown;
						print("A protoState in the '|" & fsmSymbol & "| protoFSM implementation is unnamed (you forgot the declareSelf slot).");
					end;
				if fsmFrame.fsm_private_states.(stateSymbol) then
					print("The '|" & stateSymbol & "| protoState in the '|" & fsmSymbol & "| protoFSM implementation already exists (duplicate declareSelf slot value).");
				else
					fsmFrame.fsm_private_states.(stateSymbol) := stateFrame;
				
				if stateFrame.stepChildren then
					foreach eventFrame in stateFrame.stepChildren do
						begin
							RemoveSlot(eventFrame, '_proto);
							RemoveSlot(eventFrame, 'viewBounds);
							
							if not eventSymbol := GetSlot(eventFrame, 'declareSelf) then
								begin
									eventSymbol := 'unknown;
									print("A protoEvent in the '|" & stateSymbol & "| state of the '|" & fsmSymbol & "| protoFSM implementation is unnamed (you forgot the declareSelf slot).");
								end;
							if stateFrame.(eventSymbol) then
								print("The '|" & eventSymbol & "| protoEvent in the '|" & stateSymbol & "| protoState in the '|" & fsmSymbol & "| protoFSM implementation already exists (duplicate declareSelf slot value).");
							else
								stateFrame.(eventSymbol) := eventFrame;
							
							RemoveSlot(eventFrame, 'declareSelf);
						end;
				
				RemoveSlot(stateFrame, 'declareSelf);
				RemoveSlot(stateFrame, 'stepChildren);
				
				hasGenesisState := hasGenesisState or stateSymbol = 'Genesis;
			end;
	
	if not hasGenesisState then
		print("The '|" & fsmSymbol & "| protoFSM implementation is missing the required '|Genesis| state.");
	
	if not kDebugOn then		// GoToState is a debug-only function!
		begin
			RemoveSlot(fsmFrame._proto, 'GoToState);
			RemoveSlot(fsmFrame, 'GoToState);
		end;
	RemoveSlot(fsmFrame, 'stepChildren);
end

_userproto002 :=
    {viewBounds: {left: 8, top: 8, right: 128, bottom: 72},
     DoEvent:
       func(eventSymbol, paramArray)	// SELF can be anything that inherits to the finite state machine instance frame
       begin
       	local x := fsm_private_context;
       	if not x then		// this catches the situation where the FSM is disposed before a pending delayed action/call/send executes
       		return;
       	
       	if kDebugOn then
       		if paramArray and PrimClassOf(paramArray) <> 'Array then
       			Throw('|evt.ex.msg|, "protoFSM:DoEvent 2nd argument must be Nil or Array");
       	
       	x.pendingEventQueue:EnQueue(eventSymbol);
       	x.pendingParamsQueue:EnQueue(paramArray);
       	
       	if not x.busy then
       		begin
       			x.busy := true;
       			AddDelayedSend(x.fsm, 'DoEvent_Loop, nil, x.turtle);
       		end;
       	
       	nil;
       end,
     instantiate:
       //	SELF is the finite state machine template frame, e.g.:
       //
       //	local fsm := GetLayout("myFSM"):Instantiate();
       //
       //	"myFSM" is assumed to be a layout based on protoFSM,
       
       func()
       begin
       	local obj := {	_proto:							self,
       						fsm:								nil,
       						currentStateFrame:		nil,
       						currentEventFrame:		nil,
       						fsm_private_context:	{	fsm:								nil,
       																turtle:							1,
       																level:							0,
       																busy:							nil,
       																waitView:						nil,
       																waitAborted:				nil,
       																pendingState:				'Genesis,
       																pendingEventQueue:		QueueTemplate:Instantiate(),
       																pendingParamsQueue:	QueueTemplate:Instantiate(),
       																currentState:				nil,
       																currentEvent:				nil,
       																currentParams:			nil,	},	};
       	obj.currentStateFrame := {	_proto:		obj.fsm_private_states.Genesis,
       												_parent:	obj,	};
       	obj.fsm := obj.fsm_private_context.fsm := obj;
       end,
     dispose:
       func()	// SELF is the finite state machine instance frame
       begin
       	fsm_private_context.pendingEventQueue:Reset();
       	fsm_private_context.pendingParamsQueue:Reset();
       	foreach slot in fsm_private_context do fsm_private_context.slot := nil;
       	currentStateFrame := currentEventFrame := fsm_private_context := nil;		// guaranteed to return nil so that the caller can conveniently nil out the FSM container variable
       end,
     DoEvent_Loop:
       func()	// SELF is the finite state machine instance frame
       begin
       	local x := fsm_private_context;
       	if not x then		// this catches the situation where the FSM is disposed before a pending delayed action/call/send executes
       		return;
       	
       	local ok;
       	local pendingStateFrame;
       	
       	if x.pendingState then
       		if fsm_private_states.(x.pendingState) then
       			if fsm_private_states.(x.pendingState).(x.pendingEventQueue:Peek()) then
       				ok := true;
       			else
       				begin
       					if kDebugOn then :?DebugFSM('UnknownEvent, x.pendingState, x.pendingEventQueue:Peek(), x.pendingParamsQueue:Peek());			// ignore if event not programmed
       				end;
       		else
       			begin
       				if kDebugOn then :?DebugFSM('UnknownState, x.pendingState, x.pendingEventQueue:Peek(), x.pendingParamsQueue:Peek());			// error --> remain in current state
       			end;
       	else
       		begin
       			if kDebugOn then :?DebugFSM('NilState, x.pendingState, x.pendingEventQueue:Peek(), x.pendingParamsQueue:Peek());					// machine halted
       		end;
       	
       	if not ok then
       		begin
       			currentStateFrame := nil;
       			currentEventFrame := nil;
       			
       			x.pendingEventQueue:DeQueue();		// there is a problem with this state or event
       			x.pendingParamsQueue:DeQueue();		// so remove the offending pending queue elements
       		end;
       	else
       		begin
       			x.currentState := x.pendingState;
       			x.currentEvent := x.pendingEventQueue:DeQueue();
       			x.currentParams := x.pendingParamsQueue:DeQueue();
       			
       			currentStateFrame :=	{	_proto:		fsm_private_states.(x.currentState),
       													_parent:	self,	};
       			
       			currentEventFrame :=	{	_proto:		fsm_private_states.(x.currentState).(x.currentEvent),
       													_parent:	currentStateFrame,	};
       			
       			if currentEventFrame.Action then
       				begin
       					if kDebugOn then :?TraceFSM('PreAction, x.currentState, x.currentEvent, x.currentParams);
       					
       					x.level := x.level + 1;
       					try
       						Perform(currentEventFrame, 'Action, x.currentParams);
       					onexception |evt.ex| do
       						begin
       							try
       								:?ExceptionHandler(CurrentException());
       							onexception |evt.ex| do
       								nil;
       						end;
       					x.level := x.level - 1;
       					
       					if kDebugOn then :?TraceFSM('PostAction, x.currentState, x.currentEvent, x.currentParams);
       				end;
       			
       			if currentEventFrame.nextState exists then
       				if not x.pendingState := currentEventFrame.nextState then
       					if kDebugOn then :?DebugFSM('NilNextState, x.currentState, x.currentEvent, x.currentParams);		// machine halted
       			
       			if kDebugOn then :?TraceFSM('NextState, x.pendingState, x.pendingEventQueue:Peek(), x.pendingParamsQueue:Peek());
       		end;
       	
       	if x.waitView												// check for terminal state & exit waitView if necessary
       	and x.pendingState
       	and pendingStateFrame := fsm_private_states.(x.pendingState) then
       		if pendingStateFrame.terminal then
       			begin
       				x.pendingEventQueue:Reset();
       				x.pendingParamsQueue:Reset();
       				AddDelayedCall(	func()
       											if x.waitView then
       												x.waitView:Close(), nil, 1	);
       			end;
       
       	if x.pendingEventQueue:IsEmpty() then
       		x.busy := nil;
       	else
       		AddDelayedSend(self, 'DoEvent_Loop, nil, x.turtle);
       	
       	nil;
       end,
     SetSpeed:
       func(newSpeed)		// SELF is the finite state machine instance frame
       begin
       	fsm_private_context.turtle := newSpeed;
       end,
     IsBusy:
       func()	// SELF is the finite state machine instance frame
       begin
       	fsm_private_context.busy;
       end,
     GetSpeed:
       func()	// SELF is the finite state machine instance frame
       begin
       	fsm_private_context.turtle;
       end,
     GoToState:
       // SELF is the finite state machine instance frame
       // This function is for DEBUGGING USE ONLY ! ! !
       // It is STRIPPED from the resulting package when kDebugOn = nil
       
       func(newState)
       begin
       	local x := fsm_private_context;
       	
       	x.pendingState := newState;
       	x.pendingEventQueue:Reset();
       	x.pendingParamsQueue:Reset();
       	
       	nil;
       end,
     QueueTemplate:
       {
       	Instantiate:			func()									// This is a very simple First-In-First-Out queue
       								{	_proto:		self,
       									queue:		[],	},
       	
       	Reset:					func() SetLength(queue, 0),
       	
       	Peek:					func() if Length(queue) > 0 then queue[0],		// else nil
       	
       	DeQueue:				func()
       								if Length(queue) > 0 then		// else nil
       									begin
       										local data := queue[0];
       										RemoveSlot(queue, 0);
       										data;
       									end,
       	
       	EnQueue:				func(data)
       								begin
       									AddArraySlot(queue, data);
       									nil;
       								end,
       	
       	GetQueueSize:		func() Length(queue),
       	
       	IsEmpty:				func() Length(queue) = 0,
       },
     ProtoClone:
       func(object)
       begin
       	local f := 
       		func native(obj)
       		begin
       			if not IsFrame(obj) or IsFunction(obj) then
       				Throw('|evt.ex.msg|, "ProtoClone only works with frames.");
       			
       			local new := {_proto: obj};
       			foreach slot, value in obj do
       				if IsFrame(value) and not IsFunction(value) then
       					new.(slot) := call f with (value);
       			new;
       		end;
       	
       	call f with (object);
       end,
     WaitForTerminal:
       func(options)
       begin
       	local x := fsm_private_context;
       	
       	if x.waitView
       	or x.level <> 0
       	or x.pendingEventQueue:IsEmpty() then
       		return;
       	
       	x.waitView := BuildContext(waitViewTemplate);
       	x.waitView:SetOwnerContext(x, options);
       	x.waitView:ModalDialog();
       	x.waitAborted;		// return the value of waitAborted (true = user aborted via the status slip, nil = FSM terminal state was reached normally)
       end,
     waitViewTemplate:
       {	viewClass:					clView,
       	viewFlags:					vVisible,
       	viewFormat:					vfNone,
       	viewBounds:					{	left:			0,
       											top:			0,
       											right:		0,
       											bottom:		0,	},
       	
       	statusView:					nil,
       	statusViewOptions:		nil,
        	fsmContext:					nil,
        	aborted:						nil,
        	
       	SetOwnerContext:			func(owner, options)
       										begin
       											self.statusView := nil;
       											self.statusViewOptions := options;		// frame of options the caller of WaitForTerminal is passing us (e.g.  progress messages, etc.)
       											self.fsmContext := owner;				// the fsm_private_context slot of the FSM
       											self.aborted := nil;
       										end,
       	
       	viewIdleScript:				func()
       										begin
       											statusView := BuildContext(statusViewTemplate);
       											statusView:SetOwnerContext(self, statusViewOptions);
       											statusView:ModalDialog();
       											nil;
       										end,
       	
       	viewSetupDoneScript:	func()
       										begin
       											inherited:?ViewSetupDoneScript();
       											if not statusViewOptions then
       												:SetUpIdle(2000);
       											else if statusViewOptions.delayUntilStatusVisible then
       												:SetUpIdle(if statusViewOptions.delayUntilStatusVisible <= 0 then 1 else statusViewOptions.delayUntilStatusVisible);
       										end,
       	
       	viewQuitScript:			func()
       										begin
       											if statusView then
       												statusView:Close();
       											fsmContext.waitAborted := aborted;
       											fsmContext.waitView := nil;
       										end,
       	
       	statusViewTemplate:		{	_proto:								protoStatusTemplate,
       											initialSetup:						nil,
       											waitView:							nil,
       											delayUntilAbortTimer:		nil,
       											delayUntilAbortVisible:		nil,
       											abortButtonText:				nil,
       											
       											viewIdleScript:					func()
       																					begin
       																						inherited:?viewIdleScript();
       																						local contents :=	{	name:		'vBarber,
       																														values:		{	barber:		true,	},	};
       																						
       																						if delayUntilAbortVisible then
       																							begin
       																								delayUntilAbortTimer := delayUntilAbortTimer + 300;
       																								if delayUntilAbortTimer > delayUntilAbortVisible then
       																									begin
       																										delayUntilAbortVisible := nil;
       																										contents.values.primary := {	text:			abortButtonText,
       																																					script:		func()
       																																									begin
       																																										waitView.aborted := true;
       																																										waitView:Close();
       																																									end,	};
       																										base:ViewSet(contents);
       																										return 300;
       																									end;
       																							end;
       																						
       																						base:UpdateIndicator(contents);
       																						300;
       																					end,
       											
       											viewSetupDoneScript:		func()
       																					begin
       																						inherited:?ViewSetupDoneScript();
       																						:SetUpIdle(100);
       																						self.delayUntilAbortTimer := 0;
       																					end,
       											
       											SetOwnerContext:				func(owner, options)
       																					begin
       																						self.waitView := owner;
       																						self.delayUntilAbortVisible := if options then options.delayUntilAbortVisible else 8000;
       																						self.abortButtonText := if options and options.abortButtonText then options.abortButtonText else "Abort";
       												     									self.initialSetup := {	name:		'vBarber, 
       																														values:		{	icon:					ROM_routeUpdateBitmap,
       																																			statusText:		if options then options.statusText else "Please wait...",
       																																			titleText:			if options then options.titleText else nil,
       																																			barber:				true,
       																																			primary:			nil,
       																																			closeBox:			nil,	},	};
       												     								end,
       										},
       },
     ExceptionHandler:
       func(exception)
       begin
       	local x := fsm_private_context;
       	local message :=	if x then
       									"The following exception occured in event ("
       									& x.currentEvent
       									& ") of state ("
       									& x.currentState
       									& ") of finite state machine ("
       									& x.fsm.declareSelf
       									& "):  "
       								else
       									"The following exception occured:  ";
       	
       	local exceptionStr := "<unable to create string representation of exception frame>";
       	try
       		exceptionStr := :ObjectToString(exception);
       	onexception |evt.ex| do
       		nil;
       	
       	GetRoot():Notify(kNotifyAlert, kAppName, message & exceptionStr);
       	
       	print(message);
       	print(exception);
       	if GetGlobalVar('BreakOnThrows) then
       		BreakLoop();
       	
       	nil;
       end,
     ObjectToString:
       // Converts almost any NewtonScript data type into a string representation.
       // Does NOT handle recursive/self-referencing frames.
       // Does NOT follow _proto & _parent pointers.
       // Does NOT check for out-of-memory conditions, bad object refs, et cetera.
       
       func(obj)
       begin
       	local separator := ", ";
       	local separatorLen := StrLen(separator);
       	
       	local p :=
       		func(s)
       		if EndsWith(s, separator) then
       			StrMunger(s, StrLen(s) - separatorLen, nil, nil, 0, nil)
       		else
       			s;
       	
       	local f :=
       		func(obj)
       		begin
       			(	if IsFunction(obj) then
       					"func(" & NumberStr(GetFunctionArgCount(obj)) & (if GetFunctionArgCount(obj) = 1 then " arg)" else " args)")
       				
       				else if IsFrame(obj) then
       					begin
       						local s := "{";
       						foreach slot, item in obj do
       							s := s & SPrintObject(slot) & ": " & 
       								if slot = '_parent or slot = '_proto then
       									"<ignored>" & separator
       								else
       									call f with (item);
       						call p with (s) & "}";
       					end
       				
       				else if IsArray(obj) then
       					begin
       						local s := "[";
       						foreach item in obj do
       							s := s & call f with (item);
       						call p with (s) & "]";
       					end
       				
       				else if IsString(obj) then
       					$" & obj & $"
       				
       				else if IsSymbol(obj) then
       					$' & obj
       				
       				else if IsNumber(obj) or IsInteger(obj) then
       					NumberStr(obj)
       				
       				else if IsImmediate(obj) then
       					if not obj then
       						"nil"
       					else if obj = true then
       						"true"
       					else
       						SPrintObject(obj)
       				
       				else
       					SPrintObject(obj)
       			
       			) & separator;
       		end;
       	
       	call p with (call f with (obj));
       end,
     _proto: @218
    };


constant |layout_protoFSM| := _userproto002;
// End of file protoFSM
// Beginning of file ExampleFSM

// Before Script for "Example FSM"
//	Newton Developer Technical Support Sample Code
//	ExampleFSM - An NTK Finite State Machine User Proto Implementation
//	by Jim Schram, Newton Developer Technical Support
//	Copyright ©1996 Apple Computer, Inc.  All rights reserved.
//	
//	You may incorporate this sample code into your applications without
//	restriction.  This sample code has been provided "AS IS" and the
//	responsibility for its operation is 100% yours.  You are not
//	permitted to modify and redistribute the source as "DTS Sample Code."
//	If you are going to re-distribute the source, we require that you
//	make it clear in the source that the code was descended from
//	Apple-provided sample code, but that you've made changes.


Example FSM :=
    {viewBounds: {left: 8, top: 8, right: 152, bottom: 272},
     DebugFSM:
       // If this method is defined it will be called as an aid in debugging your finite state machine.
       // 
       // reason = one of 'UnknownState, 'UnknownEvent, 'NilState, 'NilNextState
       // state = the current state symbol
       // event = the current event symbol
       // params = the parameter array for the event Action function
       
       func(reason, state, event, params)
       begin
       	local s :=	"Reason = " & :ObjectToString(reason)
       					& "\nState = " & :ObjectToString(state)
       					& "\nEvent = " & :ObjectToString(event)
       					& "\nParams = " & :ObjectToString(params);
       	
       	:MTrace(s);
       	print(SubstituteChars(s, "\n", "\t"));
       end,
     TraceFSM:
       // If this method is defined it will be called as an aid in debugging your finite state machine.
       // 
       // when = one of 'PreAction, 'PostAction, 'NextState
       // state = the current state symbol
       // event = the current event symbol
       // params = the parameter array for the event Action function
       
       func(when, state, event, params)
       begin
       	local s :=	"When = " & :ObjectToString(when)
       					& "\nState = " & :ObjectToString(state)
       					& "\nEvent = " & :ObjectToString(event)
       					& "\nParams = " & :ObjectToString(params);
       	
       	:MTrace(s);
       	print(SubstituteChars(s, "\n", "\t"));
       end,
     declareSelf: 'ExampleFSM,
     ExceptionHandler:
       func(exception)
       begin
       	inherited:?ExceptionHandler(exception);		// Implement your own exception handler here, or use the cheesy default one provided by protoFSM.
       end,
     MTrace:
       func(s)
       begin
       	SetValue(GetRoot().(kAppSymbol).vTraceBox, 'text, s);
       	RefreshViews();
       end,
     fTheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything: nil,
     debug: "Example FSM",
     _proto: _userproto002
    };

Genesis :=
    {declareSelf: 'Genesis,
     viewBounds: {left: 8, top: 16, right: 136, bottom: 56},
     terminal: true,
     debug: "Genesis",
     _proto: _userproto001
    };
AddStepForm(Example FSM, Genesis);

Create :=
    {viewBounds: {left: 8, top: 16, right: 120, bottom: 32},
     nextState: 'StateStart,
     declareSelf: 'Create,
     Action:
       func(answer)
       begin
       	fTheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything := answer;
       	print(answer);
       end,
     debug: "Create",
     _proto: _userproto000
    };
AddStepForm(Genesis, Create);





State Start :=
    {viewBounds: {left: 8, top: 64, right: 136, bottom: 128},
     declareSelf: 'StateStart,
     debug: "State Start",
     _proto: _userproto001
    };
AddStepForm(Example FSM, State Start);

Event 1 Action 1 :=
    {viewBounds: {left: 8, top: 16, right: 120, bottom: 32},
     Action:
       func()
       begin
       	:DoEvent('Event2, nil);
       end,
     nextState: 'State1,
     declareSelf: 'Event1,
     debug: "Event 1 Action 1",
     _proto: _userproto000
    };
AddStepForm(State Start, Event 1 Action 1);



Event 2 Action 3 :=
    {viewBounds: {left: 8, top: 40, right: 120, bottom: 56},
     Action:
       func()
       begin
       	:DoEvent('Event1, nil);
       end,
     nextState: 'State2,
     declareSelf: 'Event2,
     debug: "Event 2 Action 3",
     _proto: _userproto000
    };
AddStepForm(State Start, Event 2 Action 3);





State 1 :=
    {viewBounds: {left: 8, top: 136, right: 136, bottom: 176},
     declareSelf: 'State1,
     debug: "State 1",
     _proto: _userproto001
    };
AddStepForm(Example FSM, State 1);

Event 2 Action 2 :=
    {viewBounds: {left: 8, top: 16, right: 120, bottom: 32},
     nextState: 'StateEnd,
     declareSelf: 'Event2,
     Action:
       func()
       begin
       	// If there is nothing to do in an Action function, there's really no need to supply the slot.
       	// See "State 2 / Event 1 Action 4" for an example of this.
       end,
     debug: "Event 2 Action 2",
     _proto: _userproto000
    };
AddStepForm(State 1, Event 2 Action 2);





State 2 :=
    {viewBounds: {left: 8, top: 184, right: 136, bottom: 224},
     declareSelf: 'State2,
     debug: "State 2",
     _proto: _userproto001
    };
AddStepForm(Example FSM, State 2);

Event 1 Action 4 :=
    {viewBounds: {left: 8, top: 16, right: 120, bottom: 32},
     nextState: 'StateEnd,
     declareSelf: 'Event1,
     debug: "Event 1 Action 4",
     _proto: _userproto000
    };
AddStepForm(State 2, Event 1 Action 4);





State End :=
    {viewBounds: {left: 8, top: 232, right: 136, bottom: 256},
     declareSelf: 'StateEnd,
     terminal: true,
     debug: "State End",
     _proto: _userproto001
    };
AddStepForm(Example FSM, State End);



// After Script for "Example FSM"
thisView := Example FSM;
call kFSMCleanUpFunc with (thisView);


constant |layout_ExampleFSM| := Example FSM;
// End of file ExampleFSM
// Beginning of file Main.t

// Before Script for "Example FSM"
//	Newton Developer Technical Support Sample Code
//	Maint.t - An NTK Finite State Machine Example Implementation
//	by Jim Schram, Newton Developer Technical Support
//	Copyright ©1996 Apple Computer, Inc.  All rights reserved.
//	
//	You may incorporate this sample code into your applications without
//	restriction.  This sample code has been provided "AS IS" and the
//	responsibility for its operation is 100% yours.  You are not
//	permitted to modify and redistribute the source as "DTS Sample Code."
//	If you are going to re-distribute the source, we require that you
//	make it clear in the source that the code was descended from
//	Apple-provided sample code, but that you've made changes.


Example FSM :=
    {title: kAppName,
     viewBounds: {left: 0, top: 10, right: 219, bottom: 205},
     viewFormat: 83952209,
     viewSetupDoneScript:
       func()
       begin
       	:ResetFSM();
       end,
     FSM: nil,
     viewQuitScript:
       // must return the value of inherited:?viewQuitScript();
       func()
       begin
       	FSM := FSM:Dispose();
       	inherited:?viewQuitScript();		// this method is defined internally
       end,
     ResetFSM:
       func()
       begin
       	if FSM then
       		FSM := FSM:Dispose();
       	FSM := GetLayout("ExampleFSM"):Instantiate();
       	FSM:DoEvent('Create, ["The answer to the ultimate question of life the universe and everything is 42."]);
       end,
     reorienttoscreen: ROM_DefRotateFunc,
     viewSetupFormScript:
       func()
       begin
       	// resize to fit on all "small" newtons.
       	constant kMaxWidth := 240;
       	constant kMaxHeight := 336;
       	
       	local b := GetAppParams();
       	self.viewBounds := RelBounds(b.appAreaLeft, b.appAreaTop,
       										  MIN(b.appAreaWidth, kMaxWidth),
       										  MIN(b.appAreaHeight, kMaxHeight));
       end,
     debug: "Example FSM",
     _proto: @157
    };

Reset :=
    {
     buttonClickScript:
       func()
       begin
       	:ResetFSM();
       end,
     text: "Reset",
     viewBounds: {left: 82, top: 26, right: 142, bottom: 46},
     debug: "Reset",
     _proto: @226
    };
AddStepForm(Example FSM, Reset);



Event 1 :=
    {
     buttonClickScript:
       func()
       begin
       	if FSM:IsBusy() then
       		GetRoot():Notify(kNotifyAlert, kAppName, "The state machine is busy.  Please try again later.");
       	else
       		FSM:DoEvent('Event1, nil);
       end,
     text: "Event 1",
     viewBounds: {left: 34, top: 58, right: 102, bottom: 78},
     debug: "Event 1",
     _proto: @226
    };
AddStepForm(Example FSM, Event 1);



Event 2 :=
    {
     buttonClickScript:
       func()
       begin
       	if FSM:IsBusy() then
       		GetRoot():Notify(kNotifyAlert, kAppName, "The state machine is busy.  Please try again later.");
       	else
       		FSM:DoEvent('Event2, nil);
       end,
     text: "Event 2",
     viewBounds: {left: 122, top: 58, right: 190, bottom: 78},
     debug: "Event 2",
     _proto: @226
    };
AddStepForm(Example FSM, Event 2);



vTraceBox :=
    {text: "",
     viewBounds: {left: 9, top: 89, right: 218, bottom: 170},
     viewJustify: 0,
     viewFont: simpleFont9,
     debug: "vTraceBox",
     _proto: @218
    };
AddStepForm(Example FSM, vTraceBox);
StepDeclare(Example FSM, vTraceBox, 'vTraceBox);




constant |layout_Main.t| := Example FSM;
// End of file Main.t



